local chatframe = ChatFrame1; -- send FGecho text to the Combat Chat Frame (tab 2)
local friendLimit = 100;   -- 100 is the maximum the local friend list can hold
local blacklistLimit = 50; -- 50 is the maximum the local badfriend list can hold
local realm = GetCurrentRealm(); -- gets the name of the server you're on

-- STARTUP TASKS
function FGstartup(listName)
	-- make sure all the player variables are loaded before updating friend lists
	if (UnitName("player") ~= nil) then
		-- remove names from local list that where removed from the friendGlobal list
		friendGlobal_RemoveFriends(listName);
		-- add friendGlobal names to local list
		friendGlobal_LoadList(listName);
		-- add all local friends to the friendGlobal list
		friendGlobal_addAll(listName);
	end
end

-- check if the Friend list has reached 100 entries (prints error if true)
function FGisFriendFull()
    index = 0;
    count = GetFriendCount("Friend");
	-- 100 is the maximum the local friend list can hold
	if count == 100 then
		FGecho("friendGlobal: failed to add friend. Friend list is full!",255,0,0);
		return true;
    end
	return false;
end

-- check if the BadFriend list has reached 50 entries (prints error if true)
function FGisBlacklistFull()
    index = 0;
    count = GetFriendCount("BadFriend");
	-- 50 is the maximum the local badfriend list can hold
	if count == blacklistLimit then
		FGecho("friendGlobal: failed to add badfriend. Blacklist list is full!",255,0,0);
		return true;
    end
	return false;
end

-- test whether a fName is in the Friend list or not (cap insensitive)
function FGisFriend(listName, fName)
    index = GetFriendCount(listName);
	-- seach for fName in the local Friend list
	for i = 1, index, 1 do
		local name, _, _, _ ,_, _, _, _, _, _ = GetFriendInfo(listName, i );
		if (name ~= nil and string.lower(name) == string.lower(fName)) then
			--FGecho(name.." found in friend list");
			return true;
		end
	end
--	FGecho(fName.." not found in friend list");
	return false;
end

-- short-hand for printing a message to the chatframe
function FGecho(msg,red,green,blue)
	if ((red) and (green) and (b)) then
		chatframe:AddMessage(msg, red, green, blue);
	else
		chatframe:AddMessage(msg);
	end
end

-- add name to the friend list (both local and global)
function friendGlobal_Add(listName, name)
	-- check for free space in the local lists before adding
	if ((listName == "Friend" and FGisFriendFull()) or (listName == "BadFriend" and FGisBlacklistFull())) then
		return;
	end
	-- get the desired global list
	list = FGChooseList(listName);
	-- add name to friendGlobal if not already in the list
	if ( list[realm][name] == nil or list[realm][name] == "") then
		list[realm][name] = UnitName("player");
	end
	-- add name to the friend list (if not already there)
	if (not FGisFriend(listName, name)) then
		FGAdd(listName, name);
	end
	SaveList(listName);
end

-- remove name from the friend list (both local and global)
function friendGlobal_Remove(listName, name)
	-- get the desired global list
	list = FGChooseList(listName);
	-- check if name is nil
	if (name ~= nil) then
		-- remove the name from the friendGobal list
		list[realm][name] = ""
		if (listName == "Friend") then
			FGecho(name.." marked as removed from friendGlobal");
		else
			FGecho(name.." marked as removed from badFriendGlobal");
		end

		-- remove name from the friend list (if there)
		if (FGisFriend(listName, name)) then
			DelFriend(listName, name);
		end

		SaveList(listName);
	end
end

-- add all friends from the friendGlobal list to the local friend list
function friendGlobal_LoadList(listName)
	-- get the desired global list
	list = FGChooseList(listName);
	j = 0; -- count the number of names added to the local friend list
	for i, p in pairs(list[realm]) do
		-- add contacts from friendGlobal to local friend list (if not already in the list)
		if (p ~= "" and i ~= nil and not FGisFriend(listName, i)) then
			FGAdd(listName, i);
			j = j + 1;
		end
	end
	--FGecho(j.." names added to "..listName);
end

-- add all friends from the local friend list to the friendGlobal list
function friendGlobal_addAll(listName)
	-- get the desired global list
	list = FGChooseList(listName);
	j = 0; -- count the number of names added to the friendGlobal list
	-- get the name of the player character
	playerName = UnitName("player");

	-- ensure that UnitName didn't return nil (happens sometimes when the function is called too early while loading a character profile)
	if (playerName == nil) then
		if (listName == "Friend") then
			FGecho("friendGlobal: Player name returned nil. Please use the sync option to update your contacts");
		else
			FGecho("badFriendGlobal: Player name returned nil. Please use the sync option to update your contacts");
		end
		return;
	end
	index = GetFriendCount(listName);
	for i = 1, index, 1 do
		local name, _, _, _ ,_, _, _, _, _, _ = GetFriendInfo(listName, i );
		-- check if the local friend is already in the friendGlobal list
		if (name ~= nil and (list[realm][name] == nil or list[realm][name] == "")) then
			-- add name to friendGlobal
			list[realm][name] = playerName;
			if (listName == "Friend") then
				FGecho("friendGlobal: added "..name);
			else
				FGecho("badFriendGlobal: added "..name);
			end
			j = j + 1;
		end
	end
	if (listName == "Friend") then
		--FGecho(j.." names added to friendGlobal list");
	else
		--FGecho(j.." names added to badFriendGlobal list");
	end
	SaveList(listName);
end

-- remove all entries found in global list that isn't in local list
function friendGlobal_removeAll(listName)
	-- get the desired global list
	list = FGChooseList(listName);

	index = 0;
	-- iterate through the list and print each entry
	for i, p in pairs(list[realm]) do
		-- check if player i is in global list and not in local list
		if (p ~= "" and not FGisFriend(listName, i)) then
			-- remove from list
			friendGlobal_Remove(listName, i);
			index = index + 1
		end
	end
end

-- remove from the local friends list the contacts that where removed from the friendGlobal list
function friendGlobal_RemoveFriends(listName)
	-- get the desired global list
	list = FGChooseList(listName);
	j = 0; -- count the number of names removed from the local list
	index = GetFriendCount(listName);
	for i = 1, index, 1 do
		local name, _, _, _ ,_, _, _, _, _, _ = GetFriendInfo(listName, i );
		-- check if the local contact was removed from the friendGlobal list
		if (name ~= nil and (list[realm][name] ~= nil and list[realm][name] == "")) then
			-- remove name from local friend list
			DelFriend(listName, name);
			if (listName == "Friend") then
				FGecho("friendGlobal: removed "..name);
			else
				FGecho("badFriendGlobal: removed "..name);
			end
			j = j + 1;
		end
	end
	if (listName == "Friend") then
		--FGecho(j.." names removed from the local friend list");
	else
		--FGecho(j.." names removed from the local blacklist list");
	end
end

-- print a list of global friends and the character you added them with (friendName > characterName ==> friendName was added by characterName)
function friendGlobal_Print(listName)
	-- get the desired global list
	list = FGChooseList(listName);
	-- print which list is to be displayed
	if (listName == "Friend") then
		FGecho("friendGlobal:")
	else
		FGecho("badFriendGlobal:")
	end
	
	index = 0;
	-- iterate through the list and print each entry
	for i, p in pairs(list[realm]) do
		if p ~= "" then
			-- i = name    p = player name    Ex.  Silver  >  John       means            Silver was added to the list by John
			FGecho(i.."  >  "..p);
			index = index + 1
		end
	end
	-- if the list was empty, label it as empty
	if index == 0 then
		FGecho("<Empty>");
	end
end

-- clear all data from the friendGlobal list
function FG_reset(listName)
	-- get the desired global list
	list = FGChooseList(listName);
	-- iterate through the list and set all entries to nil (deletes the table entry)
	for i, p in pairs(list[realm]) do
		list[realm][i] = nil;
	end
	-- print a confirmation message
	if (listName == "Friend") then
		FGecho("friendGlobal: list cleared");
	else
		FGecho("badFriendGlobal: list cleared");
	end
	SaveList(listName);
end

-- removes all entries from the local friend list
function FG_clearLocalList(listName)
	j = 0; -- counts the number of names removed from the local list
	while GetFriendCount(listName) > 0 do
		local name, _, _, _ ,_, _, _, _, _, _ = GetFriendInfo(listName, 1 );
		-- ensure name isn't nil
		if (name == nil) then
			FGecho("Error: GetFriendInfo returned nil, terminating clear operation.");
			if (listName == "Friend") then
				FGecho(j.." names removed from the local friend list");
			else
				FGecho(j.." names removed from the local blacklist list");
			end
			return;
		end
		-- remove name from local friend list
		DelFriend(listName, name);
		if (listName == "Friend") then
			FGecho("friendGlobal: removed "..name);
		else
			FGecho("badFriendGlobal: removed "..name);
		end
		j = j + 1;
	end
	if (listName == "Friend") then
		FGecho(j.." names removed from the local friend list");
	else
		FGecho(j.." names removed from the local blacklist list");
	end
end

-- Send a whisper to name telling them which character you meet them on.
function whoAmI(listName, name)
	-- get the desired global list
	list = FGChooseList(listName);

	-- trim whitespace from around 'name'
	name = name:match("%a+");
	if (list[realm][name] ~= nil and list[realm][name] ~= "" and list[realm][name] ~= UnitName("player")) then
		SendChatMessage("I am "..list[realm][name], "WHISPER", 0, name);
	elseif (list[realm][name] ~= UnitName("player")) then
		SendChatMessage("I don't remember which character I met you on", "WHISPER", 0, name);
	elseif (name ~= nil) then
		if (listName == "Friend") then
			FGecho("friendGlobal: You met "..name.." on this character!");
		else
			FGecho("badFriendGlobal: You met "..name.." on this character!");
		end
	end
end

-- save all changes to the selected list
function SaveList(listName)
	if (listName == "Friend") then
		SaveVariables("friendGlobal_List")
	else
		SaveVariables("badFriendGlobal_List")
	end
end

-- a wrapper function for AddFriend to add a check for when name is nil
function FGAdd(listName, name)
	-- add name to friendList
	if (name ~= nil) then
		AddFriend(listName, name)
	end
end

-- returns a reference to the desired list, and initializes the table if it's still nil
function FGChooseList(listName)
	list = nil;
	if (listName == "Friend") then
		list = friendGlobal_List;
	else
		list = badFriendGlobal_List;
	end
	-- ensure the function never returns nil (always returns a table)
	if (list == nil) then
		list = {};
		list[realm] = {};
	end
	if (list[realm] == nil) then
		list[realm] = {};
	end
	return list;
end
